programming4us
           
 
 
SQL Server

SQL Server 2008 : Developing Custom Managed Database Objects (part 6) - Developing Managed Triggers

- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019
3/31/2011 11:34:05 AM

Developing Managed Triggers

Managed triggers are static methods of a .NET class decorated with the SqlTrigger attribute. SqlTrigger has three named parameters:

  • Event— A required string-valued parameter that tells SQL Server which type of trigger you’re defining, as is done when defining T-SQL triggers.

  • Target— A required string-valued parameter that tells SQL Server which schema and table you’re attaching the trigger to.

  • Name— An optional string parameter that tells the deployment routine what to call the trigger when it is created in the database.

The implementation contract for a managed trigger is only that it be a static method that returns void.

Inside the method body of a managed trigger, you need to get a reference to the execution context of the trigger so you can find out what Data Manipulation Language (DML) statement the trigger is responding to and which columns have been updated. You do this by using the SqlContext.TriggerContext object of type SqlTriggerContext. (Note that this object is null when used in nontrigger contexts.) It has the following members:

  • ColumnCount— An integer property that indicates how many columns were affected by the operation.

  • IsUpdatedColumn— A Boolean method that indicates whether the column at a specific position was updated during the operation.

  • TriggerAction— An enum that indicates which operation caused the trigger to fire. For DML triggers, this is either TriggerAction.Insert, TriggerAction.Update, or TriggerAction.Delete. For DDL triggers, the list is quite a bit longer. Refer to MSDN to see all the possible values of the TriggerAction enumeration.

  • EventData— In the case of a DDL trigger, an object of type SqlXml that contains an XML document whose content explains the DDL that just fired. (The XML content model for this object is the same as that returned by the EVENTDATA() built-in function.)

Have you ever wanted to be notified by email that some important column value in your tables has been created or updated? There are many ways to do this, including using Query Notifications. You can also accomplish this by writing a managed trigger that calls a web service, which in turn sends an email.

Up until now, you haven’t had to decrease the runtime safety of your assembly. But because certain aspects of web services use the Synchronized attribute (which means they do thread synchronization), we have to change our SQLCLR assembly’s permission set to UNSAFE.

Caution

Only the sysadmin role can upload an UNSAFE assembly to SQL Server. You should allow this uploading only when you know the code being uploaded doesn’t do anything that might compromise the integrity of the data, the server, or your job.


First, you need to create a simple web service routine that sends your email. To do this using Visual Studio 2008, you create a new local IIS website called photoserve and add to it a new web service called PhotoService.asmx. Then you replace the entire body of PhotoService.cs with the following C# code:

using System;
using System.Web.Services;
using System.Net.Mail;
using System.Configuration;

[WebService(Namespace = "urn:www-samspublishing-com:examples:sqlclr:triggers")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class PhotoService : System.Web.Services.WebService
{
[WebMethod]
public void PhotoUpdateNotify(int ProductPhotoId)
{
MailMessage m = new MailMessage();
m.Subject = "New Photo: " + ProductPhotoId.ToString();
m.From = new MailAddress("ProductPhotoService@localservername");
m.Body = "http://localhost:1347/photoserve/getphoto.aspx?ppid=" +
ProductPhotoId.ToString();
m.To.Add(new MailAddress("PhotoAdmin@ localservername "));
SmtpClient s = new SmtpClient("localservername", 25);
s.Send(m);
}
}


Of course, you need to have SMTP and IIS correctly configured on your server for this example to work completely. You also need to replace localhost and localservername and the email account names shown in the code with values that work for you.

Next, you should add a new web form called getphoto.aspx to the site. You replace the entire contents of getphoto.aspx.cs with the code in Listing 9.

Listing 9. A Web Form That Retrieves Photos from SQL Server
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Data.SqlClient;
using System.IO;

public partial class getphoto : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (Request.QueryString["ppid"] != null)
{
string ppid = Request.QueryString["ppid"].ToString();
string FileName = "photos/" + ppid + ".jpeg";
string MappedFileName = Server.MapPath(FileName);
using (SqlConnection c =
new SqlConnection(
"Data Source=(local);Initial Catalog=AdventureWorks2008;
Integrated Security=True"
)
)
{
using (SqlCommand s = new SqlCommand(
@"SELECT LargePhoto
FROM Production.ProductPhoto
WHERE ProductPhotoId = " + ppid, c))
{
c.Open();
using (SqlDataAdapter a = new SqlDataAdapter(s))
{
using (DataSet d = new DataSet())
{
a.Fill(d);
if (d.Tables.Count == 1 && d.Tables[0].Rows.Count == 1)
{

byte[] BigImg = (byte[])d.Tables[0].Rows[0]["LargePhoto"];
FileStream f =
new FileStream(
MappedFileName,
FileMode.Create,
FileAccess.Write);
f.Write(BigImg, 0, BigImg.GetUpperBound(0));
f.Close();
Response.Redirect(FileName, false);
}
else
{
Response.Write("<H2>Sorry, ProductPhotoId " + ppid
+ " was not found.</H2>");
}
}
}
}
}
}
else
{
Response.Write("<H2>A querystring value for ppid is required.</H2>");
}
}
}


Next, you add a subfolder to the site called photos. This is the place where the web form will save product photos as JPEG files and redirect the email recipient. The main body of the code in Listing 46.9 illustrates how to save LOB values to file in a succinct manner, so it may prove useful for your other applications.

You either need to give your ASP.NET user file I/O permissions on photos or have the web application impersonate a user who has those permissions.

To recap, the website code so far consists of the following: a web service (PhotoService.asmx) that generates notification emails containing URLs. These URLs in turn point to a web form (getphoto.aspx) that saves the varbinary value of Production.ProductPhoto.LargePhoto (given a particular ProductPhotoId) to the photos folder as [ProductPhotoId].jpeg.

The last item you need is the reason you’re writing this code in the first place: a managed trigger that invokes the web service to kick off the whole process. To add this, you right-click the SQLCLR project and then select Add, Trigger. Name this new trigger class Triggers.cs (the default). Then replace the entire content of Triggers.cs with the code in Listing 10.

Listing 10. A Managed Trigger That Invokes a Web Service
using System;
using System.Data;
using Microsoft.SqlServer.Server;
using System.Data.SqlClient;
using SQLCLR.photoserve;

public partial class Triggers
{
[Microsoft.SqlServer.Server.SqlTrigger(
Event = "FOR UPDATE",
Name = "Production.PhotoUpdateTrigger",
Target = "Production.ProductPhoto"
)]
public static void PhotoUpdateTrigger()
{
SqlTriggerContext stc = SqlContext.TriggerContext;
if (stc.TriggerAction == TriggerAction.Update)
{
if (stc.IsUpdatedColumn(3)) //The LargePhoto varbinary(max) column
{
using (SqlCommand s = new SqlCommand(
"SELECT DISTINCT ProductPhotoId FROM INSERTED",
new SqlConnection("context connection=true")))
{
s.Connection.Open();
using (SqlDataReader r =
s.ExecuteReader(CommandBehavior.CloseConnection))
{
PhotoService p = new PhotoService();
while (r.Read())
{
SqlContext.Pipe.Send(
"Notifying Web Service of Update for PPID: " +
r.GetInt32(0).ToString());
p.PhotoUpdateNotify(r.GetInt32(0));
}
}
}
}
}
}
}


Now that all the code is in place, all that’s left is an explanation of the code of PhotoUpdateTrigger() and a test case.

In the code in Listing 46.10, you check to see whether the current TriggerAction is TriggerAction.Update, meaning that the trigger is firing due to an update. You declare this to be true by using the Event named parameter of the SqlTrigger attribute.

Next, you select the ProductPhotoId of the updated row from the INSERTED table and connect to the database by using the context connection.

You execute the command and get your SqlDataReader (r); then you instantiate the PhotoService web service. Using the overloaded method of the Pipe object, you send a string literal informational message (equivalent to T-SQL’s print function), which tells any clients what is about to happen. You call the PhotoUpdateNotify method of the web service and pass in the ProductPhotoId, which in turn sends the email containing the link back to getphoto.aspx, which generates the photo JPEG for that ProductPhotoId.

To make the test case work, you need to make your local machine’s Network Service user a SQL Server login and a user in AdventureWorks2008 with at least db_datareader access. In addition, you might need to use the Visual Studio sgen.exe tool to create a serialization assembly for SQL2008SQLCLR.dll (which sgen.exe would, by default, name SQL2008SQLCLR.XmlSerializers.dll).

You need to load this serialization assembly into AdventureWorks2008 before loading the main assembly (using CREATE ASSEMBLY). (At the time of this writing, it was necessary to also load System.Web.dll and its dependencies into AdventureWorks2008 before loading the application assemblies.)

To test the trigger, you simply update a value of Production.ProductPhoto.LargePhoto:

UPDATE Production.ProductPhoto
SET LargePhoto = LargePhoto
WHERE ProductPhotoId = 69
go
Notifying Web Service of Update for PPID: 69
(1 row(s) affected.)

If you get an email in your test inbox, you’ve done everything right. If not, don’t fret; this is a challenging example developed mainly to show the power of managed code.

Other -----------------
- SQL Server 2008 : Profiler Usage Scenarios (part 2)
- SQL Server 2008 : Profiler Usage Scenarios (part 1) - Analyzing Slow Stored Procedures or Queries & Deadlocks
- SQL Server 2008 : Defining Server-Side Traces
- SQL Server 2008 : SQL Server Profiler - Replaying Trace Data
- SQL Server 2008 : SQL Server Profiler - Saving and Exporting Traces
- SQL Server 2008 : SQL Server Profiler - Creating Traces
- SQL Server 2008 : SQL Server Profiler Architecture
- SQL Server 2008: Administering Database Objects - Working with Tables (part 7) - Partitions
- SQL Server 2008: Administering Database Objects - Working with Tables (part 6) - Compression
- SQL Server 2008: Administering Database Objects - Working with Tables (part 5) - Sparse Columns
- SQL Server 2008: Administering Database Objects - Working with Tables (part 4) - Check Constraints
- SQL Server 2008: Administering Database Objects - Working with Tables (part 3) - Foreign Key Constraints
- SQL Server 2008: Administering Database Objects - Working with Tables (part 2) - Primary Key Constraints & Unique Constraints
- SQL Server 2008: Administering Database Objects - Working with Tables (part 1) - Default Constraints
- SQL Server 2008: Administering Database Objects - Working with Database Snapshots
- Programming with SQL Azure : WCF Data Services (part 3)
- Programming with SQL Azure : WCF Data Services (part 2) - Creating the Client Application
- Using XML in SQL Server 2008: Relational Data As XML - The FOR XML Modes (part 4) - EXPLICIT Mode
- Using XML in SQL Server 2008: Relational Data As XML - The FOR XML Modes (part 3) - AUTO Mode
- Programming with SQL Azure : WCF Data Services (part 1)
 
 
 
Top 10
 
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
- First look: Apple Watch

- 3 Tips for Maintaining Your Cell Phone Battery (part 1)

- 3 Tips for Maintaining Your Cell Phone Battery (part 2)
programming4us programming4us